﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Xml;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Xml.Linq;
using System.ComponentModel;

namespace GenIX.StyleSpace
{
// <COMBOBOX>Массив списков</COMBOBOX>
    class combobox : ICloneable, IEnumerable
    {
        public string Err;
        private List<comboList> list;
        private XDocument xdoc;
        private string path;
        public bool NoBag = false;
        private bool temp;
//<COMBOBOX>Конструктор пробует открыть XML документ</COMBOBOX>
        public combobox(string path)
        {

            this.temp = false;
            this.Err = "анализ загрузки combo :\r\n";
            this.path = Path.GetDirectoryName(Application.ExecutablePath) + "\\Styles\\" + path;
            FileInfo fn = new FileInfo(this.path);
            if (fn.Exists != true)
            {
                this.NoBag = false;
                this.Err += "ошибка чтения/записи документа, документ не найден";
                return;
            }
            try
            {
                this.xdoc = XDocument.Load(this.path);
            }
            catch
            {

                this.NoBag = false;
                this.Err += "ошибка чтения/записи документа";
                return;
            }

            this.list = new List<comboList>();
            this.NoBag = this.Load();
        }
//<COMBOBOX>Конструктор пробует создать временный XML документ</COMBOBOX>
        public combobox()
        {
            this.temp = true;
            this.path = Path.GetTempFileName();
            this.list = new List<comboList>();
            this.xdoc = new XDocument(new XElement("items"));
            this.xdoc.Declaration = new XDeclaration("1.0", "utf-8", "true");
            try
            {
                this.xdoc.Save(this.path);
            }
            catch
            {
                this.NoBag = false;
                this.Err += "ошибка чтения/записи временного документа";
                return;
            }
        }
// <LOAD>Заполняет буфер объекта, в Массив списков из фала XML</LOAD>
        private bool Load()
        {
            string err = "";
            IEnumerable<XElement> item;
            try
            {
                item = from table in xdoc.Descendants("item")
                       select table;
            }
            catch
            {
                this.Err = "ошибка не найден корень";
                this.NoBag = true;
                return false;
            }

            if (item.Count() == 0)
            {
                err += "в базе нет списков";
                return true;
            }
            int i = 0;
            //<ROW>Производим дессириализацию  XML в объект типа combobox </ROW>
            foreach (var itemXML in item)
            {
                string name = "";
                string nameText = "";
                XElement element = (XElement)itemXML;
                try
                {
                    name = element.Attribute("name").Value;
                    nameText = element.Attribute("nameText").Value;
                }
                catch
                {
                    err += "элемент №  " + i + "  не содержит атрибута name :елемент будет создан";
                    element.SetAttributeValue("name", "tempList" + i);
                    element.SetAttributeValue("nameText", "tempList" + i);
                }
                if (name == "")
                {
                    err += "элемент №  " + i + " не содержит значения атрибута name :елемент будет создан";
                    element.SetAttributeValue("name", "tempList" + i);
                    element.SetAttributeValue("nameText", "tempList" + i);
                }
                //<ROW>Производим дессириализацию  XML в объект типа combolist </ROW>
                comboList clist = new comboList(name);
                clist.nameText = nameText;
                XNode node = element.FirstNode;
                while (node != null)
                {
                    XElement elementSub = (XElement)node;
                    clist.Add(elementSub.Value.Trim());
                    node = node.NextNode;
                }
                list.Add(clist);
                i++;
            }
            if (err.Trim() == string.Empty) this.Err = "- ошибок нет\r\n";
            else this.Err += err;
            try
            {
                xdoc.Save(this.path);
            }
            catch { this.Err += "ошибка чтения/записи документа"; return false; }
            return true;
        }
//<ADD>Сохраняем список в XML и Массив списков объекта</ADD>
        public bool Add(comboList clist)
        {
            if (AddXML(clist))
            {
                this.list.Add(clist);
                return true;
            }
            else { return false; }
        }
//<CHANGE>Сохраняем измененный лист в XML</CHANGE>
        public bool Change(comboList clist)
        {
            string name = clist.name;
            if (RemoveXML(name) == false) { return false; }
            XElement element = Tample(clist);
            try
            {
                xdoc.Element("items").Add(element);
                comboList temp = Get(clist.name) as comboList;  // ишем list, в памяти, который нужно изменить
                if (temp != null)
                {
                    temp = clist; 
                    xdoc.Save(this.path);
                    return true;
                }
                else
                {
                    MessageBox.Show("Список в кэше не найдет!!!");
                    return false;
                }
            }
            catch { MessageBox.Show("Ошибка чтения/записи документа"); return false; }
        }
// <REMOVE>Удаляет список по его имени</REMOVE>
        public bool Remove(string name)
        {
            comboList temp = Get(name) as comboList;  
            if (temp != null)
            {
                if (RemoveXML(name) != false)
                {
                    try
                    {
                        xdoc.Save(this.path);
                        this.list.Remove(temp);
                    }
                    catch { MessageBox.Show("Ошибка чтения/записи документа"); return false; }
                    return true;
                }
                else return false;
            }
            else
            {
                MessageBox.Show("Список в кэше не найдет!!!");
                return false;
            }
        }
// <GET>Возвращает список </GET>
        public comboList Get(string name)
        {
            for (int i = 0; i < list.Count(); i++)
                if (list[i].name == name)
                    return list[i];
            return null;
        }
        //<GETNAME></GETNAME>
public comboList GetName(string name)
        {
            for (int i = 0; i < list.Count(); i++)
                if (list[i].nameText == name)
                    return list[i];
            return null;
        }
// <GET>Возвращает список </GET>
        public comboList Get(int i)
        {
            if ((list.Count() - 1) >= i) return list[i];
            else
                return null;
        }
// <COUNT>Возрощает количество элементов </COUNT>
        public int Count()
        {
            if (list != null)
            {
                return list.Count();
            }
            else
            {
                MessageBox.Show("Объект пуст", "Предупреждение", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return 0;
            }
        }
// <GETLISTNAME>Возвращает список имен, массива списка </GETLISTNAME>
        public string[] GetListName()
        {
            string[] temp = new string[list.Count()];
            for (int i = 0; i < list.Count(); i++) temp[i] = list[i].name;
            return temp;
        }
//<GETLIST>Возращает Массив списка (если стоит тип temp то удаляет временный файл)</GETLIST>
        public List<comboList> GetList()
        {
            if (this.temp)
            {
                File.Delete(this.path);
            }
            return this.list;
        }
//<LOADLIST>Загружает массив(перед этим обнуляет свой) списка и синхронизирует с XML</LOADLIST>
        public bool LoadList(List<comboList> list)
        {
            this.list = new List<comboList>();
            comboList tempList;
            for (int i = 0; i < list.Count(); i++)
            {
                tempList = new comboList(list[i].name);
                tempList.nameText = list[i].nameText;
                for (int j = 0; j < list[i].items.Count(); j++) tempList.items.Add(list[i].items[j]);
                this.list.Add(tempList);
            }
            var query = from table in xdoc.Descendants("item")
                        select table;
            query.Remove();
            for (int i = 0; i < this.Count(); i++)
            {
                if (this.AddXML(this.Get(i)) == false)
                {
                    MessageBox.Show("Ошибка Сохранения");
                    return false;
                }
            }
            return true;
        }
// <GETENUMERATOR>Перебор цакла foreach </GETENUMERATOR>
        public IEnumerator GetEnumerator()
        {
            return new comboboxI(this);
        }
// <REMOVE>Удаляет список из XML и синхронизирует т.е удаляем списки которых нет в List    //</REMOVE>
        private bool RemoveXML(string name)
        {
            var query = (from table in xdoc.Descendants("item")
                         where table.Attribute("name").Value == name
                         select table);
            if (query.Count() == 0)
            {
                MessageBox.Show("Список не найден в базе XML!!!");
                return false;
            }
            query.Remove();
            return true;
        }
// <REMOVELIST> удаляем списки которых нет в List</REMOVELIST>
        private void RemoveList()
        {
            var query = from table in xdoc.Descendants("item")
                        select table.Attribute("name").Value;
            List<string> existXML = query.ToList<string>();
            string[] existList = this.GetListName();
            string tempname;
            bool exist;
            for (int i = 0; i < existXML.Count(); i++)
            {
                tempname = existXML[i].Trim();
                exist = false;
                for (int j = 0; j < existList.Count(); j++)
                    if (tempname == existList[j].Trim()) exist = true;
                if (exist == false)
                {
                    var delquery = from table in xdoc.Descendants("item")
                                   where table.Attribute("name").Value.Trim() == tempname
                                   select table;
                    delquery.Remove();
                }
            }
            this.xdoc.Save(this.path);
        }
// <TAMPLE>Шаблон XML Сериализация отдельного списка в XML стандарт</TAMPLE>
        private XElement Tample(comboList curlist)
        {
            //<ROW>Производим сериализацию объекта типа combolist в XML стандарт</ROW>
            XElement xlist = new XElement("item", new XAttribute("name", curlist.name), new XAttribute("nameText", curlist.nameText));
            int count = curlist.items.Count();
            for (int i = 0; i < count; i++)
            {
                XElement temp = new XElement("row", curlist.items[i].ToString());
                xlist.Add(temp);
            }
            return xlist;
        }

//<ADD>Сохраняем список в XML /ADD>
        private bool AddXML(comboList clist)
        {
            string name = clist.name;
            //<ROW>Перед добавление нового списка проверяем не сущуствует ли он. </ROW>
            var query = (from table in xdoc.Descendants("item")
                         where table.Attribute("name").Value == name
                         select new
                         {
                             name = table.Attribute("name").Value
                         });
            if (query.Count() > 0)
            {
                MessageBox.Show("Данный список уже существует!!!...");
                return false;
            }

            XElement el = Tample(clist);
            try
            {
                xdoc.Element("items").Add(el);
                xdoc.Save(this.path);
            }
            catch
            {
                MessageBox.Show("Ошибка чтения/записи документа");
                return false;
            }
            return true;


        }

// <FLUSHTOXML>Обнавление XML: удаляем все данные из XML документа и записываем Массив списка</FLUSHXML>
        private void FlushToXML()
        {
            var query = from table in xdoc.Descendants("item")
                        select table;
            query.Remove();
            for (int i = 0; i < this.Count(); i++)
            {
                this.AddXML(this.list[i]);
            }
            this.xdoc.Save(this.path);
        }

// <CLONE>Клон объекта</CLONE>
        public object Clone()
        {
            combobox temp = new combobox();
            comboList tempList;
            temp.Err = this.Err;
            temp.NoBag = this.NoBag;

            for (int i = 0; i < this.Count(); i++)
            {
                tempList = new comboList(this.list[i].name);
                tempList.nameText = this.list[i].nameText;
                for (int j = 0; j < this.list[i].items.Count(); j++)
                    tempList.items.Add(this.list[i].items[j]);
                temp.list.Add(tempList);
            }
            temp.FlushToXML();
            return temp;
        }
    }

// <COMBOBOXI>Реализует перебор коллекции </COMBOBOXI>
    class comboboxI : IEnumerator
    {
        private int position = -1;
        private combobox combo;
        public comboboxI(combobox combo)
        {
            this.combo = combo;
        }
        public object Current
        {
            get
            {
                return this.combo.Get(this.position);
            }
        }
        public bool MoveNext()
        {
            if (position < this.combo.Count() - 1)
            {
                position++;
                return true;
            }
            else
            {
                return false;
            }
        }
        public void Reset()
        {
            this.position = -1;
        }
    }

// <COMBOLIST>Список значений</COMBOLIST>
    class comboList
    {
        public List<string> items;
        public string name;
        public string nameText;
        public comboList(string name)
        {
            this.name = name;
            items = new List<string>();
        }

// <ADD>Добавляет элемент в список </ADD>
        public void Add(string name)
        {
            items.Add(name);
        }

// <ADD>Добавляет элементы в список </ADD>
        public void Add(string[] name)
        {
            items.AddRange(name);
        }

 // <ADD>количество </ADD>
        public int Count()
        {
            return items.Count();
        }

// <REMOVE>Удаляет элемент списка</REMOVE>
        public void Remove(string name)
        {
            for (int i = 0; i < items.Count(); i++)
            {
                if (items[i] == name.Trim())
                    items.Remove(name);
            }
        }

// <GETITEMS>Возрощяет массив строк из коллекции</GETITEMS>
        public string[] GetItems()
        {
            string[] temp = new string[items.Count()];
            for (int i = 0; i < items.Count(); i++) temp[i] = items[i];
            return temp;
        }

//<LOADLIST>Загружает массив строк при этом обнуляет свой</LOADLIST>
        public void LoadList(string[] list)
        {
            this.items = new List<string>();
            this.items.AddRange(list);
        }
    }
}
